/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import main.H;
import server.ClientHandler;
import server.Server;

/**
 *
 * @author benjamin
 */
public class ServerGUI extends javax.swing.JFrame implements Runnable {

    /**
     * Creates new form ServerGUI
     */
    public ServerGUI() {
        initComponents();
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(ServerGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(ServerGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(ServerGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ServerGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
        init();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane2 = new javax.swing.JScrollPane();
        txtOutput = new javax.swing.JTextArea();
        jPanel1 = new javax.swing.JPanel();
        cmbInet = new javax.swing.JComboBox();
        txtPort = new javax.swing.JTextField();
        btnStart = new javax.swing.JButton();
        btnStop = new javax.swing.JButton();
        cmbIpAdd = new javax.swing.JComboBox();
        jScrollPane1 = new javax.swing.JScrollPane();
        lstClients = new javax.swing.JList();
        jPanel2 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        txtInput = new javax.swing.JTextField();
        btnSend = new javax.swing.JButton();
        btnKick = new javax.swing.JButton();
        btnSpawn = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        txtOutput.setColumns(20);
        txtOutput.setRows(5);
        txtOutput.setBorder(javax.swing.BorderFactory.createTitledBorder("Server log"));
        jScrollPane2.setViewportView(txtOutput);

        getContentPane().add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Server controls"));

        cmbInet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cmbInet.setPreferredSize(new java.awt.Dimension(250, 28));

        txtPort.setText("4444");
        txtPort.setBorder(null);
        txtPort.setPreferredSize(new java.awt.Dimension(75, 28));

        btnStart.setText("Start server");
        btnStart.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStartActionPerformed(evt);
            }
        });

        btnStop.setText("Stop server");
        btnStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStopActionPerformed(evt);
            }
        });

        cmbIpAdd.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(6, 6, 6)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(cmbIpAdd, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(btnStop))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(cmbInet, 0, 380, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnStart)))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnStart)
                    .addComponent(cmbInet, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cmbIpAdd, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnStop)
                    .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)))
        );

        getContentPane().add(jPanel1, java.awt.BorderLayout.PAGE_START);

        lstClients.setBorder(javax.swing.BorderFactory.createTitledBorder("Clients"));
        lstClients.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        lstClients.setPreferredSize(new java.awt.Dimension(200, 80));
        jScrollPane1.setViewportView(lstClients);

        getContentPane().add(jScrollPane1, java.awt.BorderLayout.LINE_START);

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Client controls"));

        jLabel2.setLabelFor(txtInput);
        jLabel2.setText("Message:");

        txtInput.setPreferredSize(new java.awt.Dimension(250, 20));

        btnSend.setText("Send");
        btnSend.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSendActionPerformed(evt);
            }
        });

        btnKick.setText("Kick");
        btnKick.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnKickActionPerformed(evt);
            }
        });

        btnSpawn.setText("Spawn test client");
        btnSpawn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSpawnActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(btnSpawn)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnKick))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(txtInput, javax.swing.GroupLayout.PREFERRED_SIZE, 212, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnSend)))
                .addGap(0, 130, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(txtInput, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnSend))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnSpawn)
                    .addComponent(btnKick))
                .addContainerGap())
        );

        getContentPane().add(jPanel2, java.awt.BorderLayout.PAGE_END);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed
        startServer();
    }//GEN-LAST:event_btnStartActionPerformed

    private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopActionPerformed
        stopServer();
    }//GEN-LAST:event_btnStopActionPerformed

    private void btnSendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSendActionPerformed
        sendMsgToClient();
    }//GEN-LAST:event_btnSendActionPerformed

    private void btnKickActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnKickActionPerformed
        kickClient();
    }//GEN-LAST:event_btnKickActionPerformed

    private void btnSpawnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSpawnActionPerformed
        spawnClient();
    }//GEN-LAST:event_btnSpawnActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnKick;
    private javax.swing.JButton btnSend;
    private javax.swing.JButton btnSpawn;
    private javax.swing.JButton btnStart;
    private javax.swing.JButton btnStop;
    private javax.swing.JComboBox cmbInet;
    private javax.swing.JComboBox cmbIpAdd;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JList lstClients;
    private javax.swing.JTextField txtInput;
    private javax.swing.JTextArea txtOutput;
    private javax.swing.JTextField txtPort;
    // End of variables declaration//GEN-END:variables
    
    private Server server = null;
    private Thread serverThread = null;
    private javax.swing.Timer timer = null;
    private DefaultListModel clientListModel;
    private DefaultComboBoxModel inetComboBoxModel;
    private DefaultComboBoxModel ipAddComboBoxModel;
    private List<NetworkInterface> inetList;
    private List<InetAddress> ipAddList;

    private void init() {
        this.btnStop.setEnabled(false);
        this.clientListModel = new DefaultListModel();
        this.inetComboBoxModel = new DefaultComboBoxModel();
        this.ipAddComboBoxModel = new DefaultComboBoxModel();
        this.lstClients.setModel(clientListModel);
        this.cmbInet.setModel(inetComboBoxModel);
        this.cmbIpAdd.setModel(ipAddComboBoxModel);
        this.cmbInet.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (cmbInet.hasFocus()) {
                    fillInetAddresses();
                }
            }
        });
        fillInterfaceCombo();
        timer = new javax.swing.Timer(100, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                onTimerTick();
            }
        });
        timer.start();
    }

    private void onTimerTick() {
        if (server == null) {
            return;
        }

        ClientHandler ch = server.getLastConnectedClient();
        if (ch != null) {
            clientListModel.addElement(ch.getName());
        }

        String message = server.getMessage();
        if (message == null) {
            return;
        }

        wl(message);
    }

    private void wl(String data) {
        this.txtOutput.append(data + System.lineSeparator());
    }

    @Override
    public void run() {
        setVisible(true);
        pack();
    }

    private void fillInterfaceCombo() {
        try {
            this.inetList = new ArrayList<NetworkInterface>();
            Enumeration<NetworkInterface> inets = NetworkInterface.getNetworkInterfaces();
            for (NetworkInterface netint : Collections.list(inets)) {
                if (netint.isUp()) {
                    inetComboBoxModel.addElement(netint.getDisplayName());
                    inetList.add(netint);
                }
            }
        } catch (SocketException ex) {
            ex.printStackTrace();
        }
    }

    private void fillInetAddresses() {
        this.ipAddList = new ArrayList<InetAddress>();
        this.ipAddComboBoxModel.removeAllElements();
        Enumeration<InetAddress> netints = inetList.get(cmbInet.getSelectedIndex()).getInetAddresses();
        for (InetAddress netadd : Collections.list(netints)) {
            this.ipAddComboBoxModel.addElement(netadd.getHostAddress());
            this.ipAddList.add(netadd);
        }
    }

    private InetAddress getselectedInetAdd() {
        return ipAddList.get(this.cmbIpAdd.getSelectedIndex());
    }

    private void startServer() {
        this.clientListModel.clear();
        int port = Integer.parseInt(this.txtPort.getText());
        server = new Server(port, getselectedInetAdd());
        this.txtPort.setText("" + server.getPort());
        serverThread = new Thread(server);
        serverThread.start();
        this.btnStart.setEnabled(false);
        this.btnStop.setEnabled(true);
    }

    private void stopServer() {
        server.stop();
        serverThread.interrupt();
        this.btnStart.setEnabled(true);
        this.btnStop.setEnabled(false);
    }

    private void sendMsgToClient() {
        String message = this.txtInput.getText();
        //javax.swing.JOptionPane.showMessageDialog(null, this.lstClients.getSelectedIndex());
        server.sendMessageToClient(getSelectedClient(), "[SERVER]: " + message);
    }

    private void kickClient() {
        getSelectedClient().kill();
    }

    private ClientHandler getSelectedClient() {
        if (server == null) {
            return null;
        }
        return server.getClient(this.lstClients.getSelectedIndex()+1);
    }

    private void spawnClient() {
        new Thread(new ClientGUI()).start();
    }
}
